import asyncio
from typing import Awaitable, List, Dict, Any, Optional, Coroutine

from fastapi import HTTPException
from sqlalchemy import desc, select, func, or_
from sqlalchemy.ext.asyncio import AsyncSession
from starlette import status

from common.GlobalConfig import config
from common.sqlalchemy_db import SqlalchemyX
from common.util import singleton
from modules.http_resp import ResponseFail, ResponseSuccess
from modules.mod import Dialog, Message
from service.GroupDBService import GroupDBService
from service.GroupService import GroupService
from service.MessageService import MessageService
from service.UserService import UserService
from common.GlobalConfig import config


@singleton
class DialogService:

    def __init__(self, session: AsyncSession = SqlalchemyX.AsyncSessionLocal() ):
        self.session = session
        self.user_service = UserService()
        self.message_service = MessageService()
        self.group_service = GroupService()
        self.group_db_service = GroupDBService()

    async def get_dialog_list_by_user_id(self, user_id: str, page: int, limit: int) -> ResponseSuccess:

        async with SqlalchemyX.AsyncSessionLocal() as session:
            skip = (page - 1) * limit
            query = select(Dialog).where(Dialog.dialog_from_id == user_id).order_by(Dialog.dialog_last_time.desc()).offset(
                skip).limit(limit)
            result = await session.execute(query)
            dialogs = result.scalars().all()
            dialogList = await self.resolve_dialog_list(dialogs)

            total_query = select(func.count('*')).select_from(Dialog).where(Dialog.dialog_from_id == user_id)
            total_result = await self.session.execute(total_query)
            total = total_result.scalar_one()
            # 手动将 dialogs 转换为字典列表
            return ResponseSuccess({
                    "curPage": page,
                    "listNum": len(dialogs),
                    "pageSum": (total + limit - 1) // limit,  # 计算总页数
                    "dialogList": dialogList
            })

    async def resolve_dialog_list(self, dialogs: List[Dialog]) -> List[Dict[str, Any]]:
        dialog_promise_list = [
            await self._resolve_single_dialog(dialog) for dialog in dialogs
        ]
        return dialog_promise_list

    async def _resolve_single_dialog(self, dialog: Dialog) -> Dict[str, Any]:
        dialog_id = dialog.dialog_id
        dialog_target_id = dialog.dialog_target_id
        dialog_from_id = dialog.dialog_from_id
        last_message_id = dialog.last_message_id
        dialog_last_time = dialog.dialog_last_time
        target_type = await self.get_dialog_target_type(dialog)
        target_mes = await self.get_target_mes(target_type, dialog_target_id)
        if not last_message_id:
            return {
                "dialogId": dialog_id,
                "dialogTargetId": dialog_target_id,
                "dialogFromId": dialog_from_id,
                "dialogTarget": target_mes,
                "dialogLastTime": dialog_last_time.strftime("%Y-%m-%d %H:%M:%S"),
                "lastMessage": {
                    "messageContent": "暂无消息",
                    "messageContentType": "text",
                    "messageCreatedTime": dialog_last_time
                }
            }
        lastMessage = {}
        if last_message := (await self.message_service.find_message_by_option({
            "message_id": last_message_id
        })):
            last_message = last_message[0]
            lastMessage["messageFromId"] = last_message.message_from_id
            lastMessage["messageType"] = last_message.message_type
            lastMessage["messageContent"] = last_message.message_content
            lastMessage["messageContentType"] = last_message.message_content_type
            lastMessage["messageCreatedTime"] = last_message.message_created_time
            lastMessage["messageFromName"] = (await self.user_service.get_user_basic_mes({"user_id": last_message.message_from_id}))["user_name"]
        return {
            "dialogId": dialog_id,
            "dialogTargetId": dialog_target_id,
            "dialogFromId": dialog_from_id,
            "dialogTarget": target_mes,
            "dialogLastTime": dialog_last_time,
            "lastMessage": lastMessage
        }

    async def update_dialog_mes(self, option, create_dialog_mes, update_content):
        check_query = select(Dialog).filter_by(**option)
        result = await self.session.execute(check_query)
        dialog = result.scalars().first()

        if not dialog:
            # 创建新的对话
            new_dialog = Dialog(**create_dialog_mes)
            self.session.add(new_dialog)
        else:
            # 更新现有对话
            for key, value in update_content.items():
                setattr(dialog, key, value)

        await self.session.commit()

    # 检查dialog是否存在，并返回该dialog信息
    async def check_and_get_dialog_mes(self, option: Dict[str, Any]) -> dict:
        async with SqlalchemyX.AsyncSessionLocal() as session:
            query = select(Dialog)

            # 根据传入的选项构建查询条件
            for key, value in option.items():
                if hasattr(Dialog, key):
                    query = query.where(getattr(Dialog, key) == value)

            result = await session.execute(query)
            dialog = result.scalars().first()
            if not dialog:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail=f"该对话不存在",
                    headers={"WWW-Authenticate": "Bearer"},
                )
            return dialog

    async def get_target_mes(self, target_type: str, dialog_target_id: str) -> dict:
        if target_type == "user":
            target_mes = await self.user_service.get_user_basic_mes({"user_id": dialog_target_id})
            return {
                "targetType": target_type,
                "targetId": target_mes["user_id"],
                "targetName": target_mes["user_name"],
                "targetAvatar": target_mes["user_avatar"],
                "targetState": target_mes["user_state"]
            }
        elif target_type == "group":
            target_mes = await self.group_db_service.get_group_mes({"group_id": dialog_target_id})
            return {
                "targetType": target_type,
                "targetId": target_mes.group_id,
                "targetName": target_mes.group_name,
                "targetAvatar": target_mes.group_avatar,
                "targetState": 1
            }
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="无效的目标类型"
            )

        # 获取对话目标类型（私聊还是群聊）
    async def get_dialog_target_type(
                self,
                dialog: Dialog
        ) -> str:
            # 使用属性访问而不是字典访问
            dialog_target_id = dialog.dialog_target_id
            if dialog_target_id is None:
                raise ValueError("Missing 'dialog_target_id' in dialog.")

            # 使用实例服务
            user_service = self.user_service
            group_service = self.group_service

            # 检查目标是否为用户
            if await user_service.check_user_existence({"user_id": dialog_target_id}):
                return 'user'
            # 检查目标是否为群组
            elif await group_service.check_group_exists(dialog.dialog_target_id):
                return 'group'
            # 如果都不是，抛出错误
            else:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="目标用户不存在"
                )

    async def find_message_by_option(self, option: dict) -> Awaitable[list]:
        stmt = select(Message)  # 假设 Message 是你的 ORM 模型

        if "where" in option:
            where_conditions = []

            if isinstance(option["where"], list):
                for cond in option["where"]:
                    if "message_from_id" in cond and "message_to_id" in cond:
                        where_conditions.append(
                            (Message.message_from_id == cond["message_from_id"]) &
                            (Message.message_to_id == cond["message_to_id"])
                        )
            elif isinstance(option["where"], dict):
                if "message_from_id" in option["where"] and "message_to_id" in option["where"]:
                    where_conditions.append(
                        (Message.message_from_id == option["where"]["message_from_id"]) &
                        (Message.message_to_id == option["where"]["message_to_id"])
                    )
                else:
                    # 处理其他单个字段条件
                  for key, value in option["where"].items():
                    if hasattr(Message, key):
                        where_conditions.append(getattr(Message, key) == value)    

            if where_conditions:
                stmt = stmt.where(where_conditions[0] if len(where_conditions) == 1 else or_(*where_conditions))

        if "order" in option:
            order_field = getattr(Message, list(option["order"].keys())[0])
            if option["order"].get(list(option["order"].keys())[0]) == "DESC":
                stmt = stmt.order_by(desc(order_field))
            else:
                stmt = stmt.order_by(order_field)

        if "skip" in option and isinstance(option["skip"], int):
            stmt = stmt.offset(option["skip"])

        if "take" in option and isinstance(option["take"], int):
            stmt = stmt.limit(option["take"])

        async with SqlalchemyX.AsyncSessionLocal() as session:
            result = await session.execute(stmt)
            return result.scalars().all()

    async def resolve_history_message(self, history_messages: List[Message]) -> List[Dict]:
        resolved_messages = []

        for message in history_messages:
            from_id = message.message_from_id
            to_id = message.message_to_id
            message_type = message.message_type

            # 获取发送者信息
            from_user = await self.user_service.get_user_basic_mes({"user_id": from_id})
            if not from_user:
                continue  # 或 raise 错误

            # 获取接收者信息（用户 or 群组）
            if message_type == 0:
                to_user = await self.user_service.get_user_basic_mes({"user_id": to_id})
                if not to_user:
                    continue
                message_to_mes = {
                    "targetId": to_user["user_id"],
                    "targetName": to_user["user_name"],
                    "targetAvatar": to_user["user_avatar"],
                    "targetState": to_user["user_state"]
                }
            else:
                group_result = await self.group_service.get_group_mes(self.session, {"group_id": to_id})
                group_list = list(group_result)  # 将迭代器转换为列表
                if not group_list or len(group_list) == 0:
                    continue
                group = group_list[0]  # 获取第一个元素
                message_to_mes = {
                    "targetId": group["group_id"],
                    "targetName": group["group_name"],
                    "targetAvatar": group["group_avatar"],
                    "targetState": 1  # 群组统一状态为1
                }

            # 构造返回格式
            resolved_messages.append({
                "messageId": message.message_id,
                "messageFromMes": {
                    "fromId": from_user["user_id"],
                    "fromName": from_user["user_name"],
                    "fromAvatar": from_user["user_avatar"],
                    "fromState": from_user["user_state"]
                },
                "messageToMes": message_to_mes,
                "messageType": message.message_type,
                "messageContent": message.message_content,
                "messageContentType": message.message_content_type,
                "messageCreatedTime": message.message_created_time,
                "messageState": message.message_state
            })

        return resolved_messages

    async def get_messages_by_option(self, option: Dict[str, Any]):
        """
        通过指定条件获取消息
        :param option: 查询条件
        :return: 消息列表
        """
        try:
            messages =  await self.find_message_by_option(option)
            return messages
        except Exception as e:
            raise ResponseFail(f"Error fetching messages: {str(e)}")

    async def get_history_message_by_target_type(
            self,
            dialog_target_type: str,
            dialog: Dialog,
            extra_option: Optional[Dict[str, Any]] = None):
        user_option = {
            "where": [
                {
                    "message_from_id": dialog.dialog_from_id,
                    "message_to_id": dialog.dialog_target_id
                },
                {
                    "message_from_id": dialog.dialog_target_id,
                    "message_to_id": dialog.dialog_from_id
                }
            ]
        }

        group_option = {
            "where": {
                "message_to_id": dialog.dialog_target_id
            }
        }

        # 合并 extra_option 到主选项中
        if extra_option:
            def merge_options(base, extra):
                merged = base.copy()
                for key, value in extra.items():
                    if key in merged and isinstance(merged[key], dict) and isinstance(value, dict):
                        merged[key].update(value)
                    else:
                        merged[key] = value
                return merged

            user_option = merge_options(user_option, extra_option)
            group_option = merge_options(group_option, extra_option)

        if dialog_target_type == "user":
            return await self.get_messages_by_option(user_option)
        else:
            return await self.get_messages_by_option(group_option)